"""
体重记录 Services 层（优化版）
核心变更：提交日期重复则更新，否则新增
"""
from datetime import datetime, date
from typing import Optional

import numpy as np
import pandas as pd

from app.Dao.HealthDao.WeightDao.WeightDao import WeightDAO
from app.Models.HealthModels.WeightModels.WeightModel import Weight
from app.Services.HealthServices.FoodServices.FoodRecordServices import FoodRecordServices
from datetime import date


class WeightServices:
    @staticmethod
    def add_or_update_weight(user_id: int, weight: float, submit_time=None) -> tuple[bool, str]:
        """
        新增或更新体重记录（核心方法）
        逻辑：同一用户+同一日期 → 更新；否则 → 新增
        :param user_id: 用户ID
        :param weight: 体重（kg）
        :param date_str: 提交日期字符串（格式：yyyy-MM-dd，可选，默认当前日期）
        :return: (是否成功, 提示信息)
        """
        # 1. 基础参数校验
        if not isinstance(user_id, int) or user_id <= 0:
            return False, f"用户ID无效（必须为正整数）：{user_id}"

        if not isinstance(weight, (int, float)) or weight <= 0 or weight > 300:
            return False, f"体重无效（必须为0-300kg之间的数值）：{weight}"

        # 提取纯日期（用于判断重复：忽略时分秒，只比较年月日）
        target_date = submit_time.date()
        # 构造当天时间范围（00:00:00 到 23:59:59）
        day_start = datetime.combine(target_date, datetime.min.time())
        day_end = datetime.combine(target_date, datetime.max.time())

        # 3. 查询该用户当天是否已有记录
        try:
            existing_weights, _ = WeightDAO.get_weights_by_user(
                user_id=user_id,
                start_date=day_start,
                end_date=day_end
            )
        except Exception as e:
            return False, f"查询历史记录失败：{str(e)}"

        # 4. 业务逻辑：有记录则更新，无记录则新增
        try:
            if existing_weights:
                # 有重复日期 → 更新第一条记录（同一用户同一天理论上只有一条）
                weight_id = existing_weights[0].id
                updated_weight = WeightDAO.update_weight(
                    weight_id=weight_id,
                    new_weight=weight,
                    new_submit_time=submit_time  # 可选：更新提交时间为当前操作时间
                )
                if not updated_weight:
                    return False, f"更新失败：未找到ID为{weight_id}的体重记录"
                return True, f"日期{target_date.strftime('%Y-%m-%d')}已存在记录，已更新体重为{weight}kg（记录ID：{weight_id}）"
            else:
                # 无重复日期 → 新增记录
                new_weight = WeightDAO.add_weight(
                    user_id=user_id,
                    weight=weight,
                    submit_time=submit_time
                )
                return True, f"体重记录新增成功（日期：{target_date.strftime('%Y-%m-%d')}，体重：{weight}kg，记录ID：{new_weight.id}）"
        except Exception as e:
            return False, f"操作失败：{str(e)}"

    # ---------------------- 以下方法保持不变，仅补充完整 ----------------------
    @staticmethod
    def get_weight_by_id(weight_id: int, user_id: int = None) -> tuple[bool, str, Optional[Weight]]:
        if not isinstance(weight_id, int) or weight_id <= 0:
            return False, f"记录ID无效（必须为正整数）：{weight_id}", None

        try:
            weight = WeightDAO.get_weight_by_id(weight_id)
            if not weight:
                return False, f"未找到ID为{weight_id}的体重记录", None

            if user_id and weight.user_id != user_id:
                return False, f"无权限访问ID为{weight_id}的体重记录（归属用户不匹配）", None

            return True, f"查询ID为{weight_id}的体重记录成功", weight
        except Exception as e:
            return False, f"查询体重记录失败：{str(e)}", None

    @staticmethod
    def get_weights_by_user(
            user_id: int,
            start_date_str: str = None,
            end_date_str: str = None,
            page: int = 1,
            per_page: int = 20
    ):
        if not isinstance(user_id, int) or user_id <= 0:
            return False, f"用户ID无效（必须为正整数）：{user_id}"

        if not isinstance(page, int) or page < 1:
            return False, f"页码无效（必须为正整数）：{page}"

        if not isinstance(per_page, int) or per_page < 1 or per_page > 100:
            return False, f"每页条数无效（必须为1-100之间的整数）：{per_page}"

        start_date = None
        end_date = None
        print(start_date_str, end_date_str)
        try:
            if start_date_str:
                start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
            if end_date_str:
                end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
                end_date = datetime.combine(end_date.date(), datetime.max.time())
        except ValueError:
            return False, f"日期格式错误（请传入 yyyy-MM-dd 格式）"

        try:
            print(start_date, end_date)
            weights, total = WeightDAO.get_weights_by_user(
                user_id=user_id,
                start_date=start_date,
                end_date=end_date,
                page=page,
                per_page=per_page
            )
            print(weights[0].weight)
            return weights, total
        except Exception as e:
            return False, f"查询用户{user_id}体重记录失败：{str(e)}"

    # 计算用户的BMR
    @staticmethod
    def cal_bmr(user_id: int, bmr_date: str):
        """
        根据用户ID|日期计算具体用户的当日基础代谢值。
        按照《我的最后一本减肥书》中的BMR计算公式。-默认男性，后续新增女性吧。
        毛德倩公式：(体重kg * 48.5 + 2954.7) / 4.184
        """
        weight, total = WeightServices.get_weights_by_user(user_id, start_date_str=bmr_date, end_date_str=bmr_date)
        try:
            # 今日总基础代谢值
            bmr = (weight[0].weight * 48.5 + 2954.7) / 4.184 * 1.5
            # 今日的饮食摄入总热量
            _, food_intake_kcal = FoodRecordServices.get_all_food_records(user_id, start_date=date.today(),
                                                                                       end_date=date.today())
            food_intake_kcal = pd.DataFrame(food_intake_kcal['items'])
            if len(food_intake_kcal) == 0:
                act_intake_kcal = 0
            else:
                act_intake_kcal = np.round(float(food_intake_kcal['act_intake_kcal'].sum()), 2)
            # 剩余可摄入代谢值
            rest_bmr = np.round(bmr - act_intake_kcal, 2)
        except Exception as e:
            return False, f"该日期没有体重记录，无法计算BMR，请补充该日期的体重值。{e}"
        return True, {
            'weight': weight[0].weight,
            'bmr': bmr,
            "rest_bmr": rest_bmr
        }

    @staticmethod
    def get_latest_weight(user_id: int) -> tuple[bool, str, Optional[Weight]]:
        """
        获取最新的体重记录。
        """
        if not isinstance(user_id, int) or user_id <= 0:
            return False, f"用户ID无效（必须为正整数）：{user_id}", None

        try:
            latest_weight = WeightDAO.get_latest_weight(user_id)
            if not latest_weight:
                return False, f"用户{user_id}暂无体重记录", None

            return True, f"查询用户{user_id}最新体重记录成功（{latest_weight.submit_time.strftime('%Y-%m-%d')}：{latest_weight.weight}kg）", latest_weight
        except Exception as e:
            return False, f"查询用户{user_id}最新体重记录失败：{str(e)}", None

    @staticmethod
    def update_weight(
            weight_id: int,
            user_id: int,
            new_weight: float = None,
            new_date_str: str = None
    ) -> tuple[bool, str]:
        """
        更新体重记录
        """
        if not isinstance(weight_id, int) or weight_id <= 0:
            return False, f"记录ID无效（必须为正整数）：{weight_id}"

        if not isinstance(user_id, int) or user_id <= 0:
            return False, f"用户ID无效（必须为正整数）：{user_id}"

        if new_weight is None and new_date_str is None:
            return False, "未传入任何更新字段（体重或日期至少需传入一个）"

        success, msg, weight = WeightServices.get_weight_by_id(weight_id, user_id)
        if not success:
            return False, msg

        update_params = {}
        if new_weight is not None:
            if not isinstance(new_weight, (int, float)) or new_weight <= 0 or new_weight > 300:
                return False, f"新体重无效（必须为0-300kg之间的数值）：{new_weight}"
            update_params["new_weight"] = new_weight

        if new_date_str is not None:
            try:
                new_submit_time = datetime.strptime(new_date_str, "%Y-%m-%d")
                update_params["new_submit_time"] = new_submit_time
            except ValueError:
                return False, f"新日期格式错误（请传入 yyyy-MM-dd 格式）：{new_date_str}"

        if new_date_str:
            new_date = new_submit_time.date()
            day_start = datetime.combine(new_date, datetime.min.time())
            day_end = datetime.combine(new_date, datetime.max.time())

            existing_weights, _ = WeightDAO.get_weights_by_user(
                user_id=user_id,
                start_date=day_start,
                end_date=day_end
            )
            existing_weights = [w for w in existing_weights if w.id != weight_id]
            if existing_weights:
                return False, f"用户{user_id}在{new_date_str}已存在其他体重记录，不可重复"

        try:
            updated_weight = WeightDAO.update_weight(
                weight_id=weight_id, **update_params
            )
            if not updated_weight:
                return False, f"更新失败：未找到ID为{weight_id}的体重记录"

            return True, f"体重记录更新成功（ID：{weight_id}）"
        except Exception as e:
            return False, f"体重记录更新失败：{str(e)}"

    @staticmethod
    def delete_weight(weight_id: int, user_id: int) -> tuple[bool, str]:
        """
        删除体重记录
        """
        if not isinstance(weight_id, int) or weight_id <= 0:
            return False, f"记录ID无效（必须为正整数）：{weight_id}"

        if not isinstance(user_id, int) or user_id <= 0:
            return False, f"用户ID无效（必须为正整数）：{user_id}"

        success, msg, weight = WeightServices.get_weight_by_id(weight_id, user_id)
        if not success:
            return False, msg

        try:
            delete_success = WeightDAO.delete_weight(weight_id)
            if not delete_success:
                return False, f"删除失败：未找到ID为{weight_id}的体重记录"

            return True, f"体重记录删除成功（ID：{weight_id}）"
        except Exception as e:
            return False, f"体重记录删除失败：{str(e)}"

    @staticmethod
    def delete_weights_by_user(user_id: int, operator_id: int) -> tuple[bool, str]:
        """
        根据用户ID删除体重记录。
        """
        if not isinstance(user_id, int) or user_id <= 0:
            return False, f"用户ID无效（必须为正整数）：{user_id}"

        if not isinstance(operator_id, int) or operator_id <= 0:
            return False, f"操作人ID无效（必须为正整数）：{operator_id}"

        # 权限校验示例（根据实际系统调整）
        # is_admin = UserService.is_admin(operator_id)
        # if not is_admin and operator_id != user_id:
        #     return False, f"操作人{operator_id}无权限删除用户{user_id}的体重记录"

        try:
            delete_count = WeightDAO.delete_weights_by_user(user_id)
            return True, f"批量删除用户{user_id}体重记录成功（共删除{delete_count}条）"
        except Exception as e:
            return False, f"批量删除用户{user_id}体重记录失败：{str(e)}"
